/*
 * @Author: gukeming
 * @Date: 2020-04-28 14:29:23
 * @Last Modified by: ningguilin
 * @Last Modified time: 2020-09-27 18:46:30
 */

;(function(win) {
    var appParams;
    var ua = navigator.userAgent;
    
    var conf = {};
    var nativeCall = {};
    
    var reqInterceptor = function(req){return req};
    var resInterceptor = function(res){return res};

    function getAppVersion() {
        var dsApp = ua.match(/(DSApp);?[\s\/]+([\d.]+)?/);
        if (dsApp) {
            return dsApp[2]
        }
        return "";
    }

    function isAndroid() {
        return ua.indexOf('Android') > 0;
    }

    function isFlutter() {
        return /(flutter)/i.test(ua);
    }

    function isIOS() {
        return /(iPhone|iPad|iPod)/i.test(ua);
    }

    function log(msg) {
        if(conf.debug) {
            console.log("jDsSdk:",msg);
        }
    }

    /**
     * 将url字符串转为json对象形式简单版 ?a=1&b=2 -> {a:1,b:2}
     * 复杂对象使用qs.parse()
     * @param params
     */
    function url2json(urlStr) {
        var ret = {};
        urlStr.replace(/([^?&]+)=([^?&]+)/g, function(_, b, c) {
        ret[b] = decodeURIComponent(c);
        });

        log("url2json params=" + JSON.stringify(ret));
        return ret;
    }

    /**
     * 发送事件
     * @param {*} type 
     */
    function dispatchEvent(type){
        var ev = document.createEvent('Event');
        ev.initEvent(type, true, true);
        document.dispatchEvent(ev);
    }

    /**
     * 处理请求回调
     * @param {*} callback 
     * @param {*} req 
     */
    function resultHandler(callback, req) {
        var callbackId = 'callbackId_' + Date.now() + '_' + Math.ceil(Math.random() * 10);
        window[callbackId] = function(result) {
            log(result);

            var resultObj = null;
            if (result !== void 0 && result !== 'null' && result !== null) {
                resultObj = JSON.parse(result);
            }

            if (resInterceptor) {
                resultObj = resInterceptor(resultObj, req);
            }

            if (resultObj && typeof(callback) === 'function') {
                callback(resultObj, req);
            }
            
            //如果不是持续回调，就删除，避免内存泄漏
            if(!resultObj || !resultObj.keepCallback) {
                delete window[callbackId];
            }
        }

        return callbackId;
    }

    /**
        *调用app端的方法
        * @param plugin 插件名称
        * @param method 方法名称
        * @param params 参数
        * @param callback 调用结果回调函数
        */
    function call(plugin, method, params, callback) {
        var req = {
            'plugin': plugin,
            'method': method,
            'params': params
        };
        
        log("调用参数：" + JSON.stringify(req));

        //拦截器拦截请求处理
        if (reqInterceptor) {
            req = reqInterceptor(req);

            if(!req || !req.plugin || !req.method) {
                log("请求拦截器返回参数有问题");
                return;
            }
        }

        var callbackId = "";
        //如果有回调函数就生成callbackId，没有就不生成，避免内存泄漏
        if (typeof(callback) === 'function') {
            callbackId = resultHandler(callback, req);
        }
        req.callbackId = callbackId;

        if (isIOS()) {
            win.webkit.messageHandlers.dsbridge.postMessage(JSON.stringify(req));
        } else if (isAndroid()) {
            win.dsbridge.invoke(JSON.stringify(req));
        }  else if (isFlutter()) {
            win.dsbridge.postMessage(JSON.stringify(req));
        }else {
            log("平台不支持，请检查");
        }
    }
  
      
    var mobile = {
        dispatchEvent: dispatchEvent,
        getAppVersion: getAppVersion,
        config: function(initConf) {
            initConf = initConf || {};
            conf.debug =  initConf.debug || false;
            conf.setting = initConf.setting || {};
        },

        setReqInterceptor: function(interceptor) {
            if(typeof(interceptor) !== 'function') {
                log("setReqInterceptor 参数必须为函数");
                return;
            }

            reqInterceptor = interceptor;
        },

        setResInterceptor: function(interceptor) {
            if(typeof(interceptor) !== 'function') {
                log("setReqInterceptor 参数必须为函数");
                return;
            }

            resInterceptor = interceptor;
        },

        /**
         * 获取url参数
         * @param {*} key 
         */
        getQueryParam: function(key) {
            var reg = new RegExp('(^|&)' + key + '=([^&]*)(&|$)', 'i');
            var r = window.location.search.substr(1).match(reg);
            
            return r !== null ? decodeURIComponent(r[2]): null;
        },

        /**
         * 获取全部url参数
         */
        getQueryParams: function() {
            var search = window.location.search;
            if (search) {
                return url2json(search);
            }
            
            return {};
        },

        /**
         * 获取app注入的参数
         * @param {*} key  参数名称
         */
        getAppParam: function(key) {
            if (!appParams && window.__APP_PARAMS__) {
                appParams = JSON.parse(window.__APP_PARAMS__);
            }

            if(appParams) {
                return appParams[key]
            }
            return void 0
        },

        /**
         * 原生方法调用jDsSdk.invoke('navigator.goBack', function(result){})
         * @param {*} pluginMethod 
         * @param {*} params 
         * @param {*} callback 
         */
        invoke: function(pluginMethod, params, callback) {
            if(typeof(pluginMethod) !== 'string') {
                log("方法参数必须是字符串");
                return;
            }
             
            var arrs = pluginMethod.split('.');
            if(arrs.length !== 2) {
                log("方法参数必须是plugin.method形式");
                return;
            }

            call(arrs[0], arrs[1], params, callback);
        },

        /**
         * 添加原生调用的方法
         * @param {string} method  方法名称
         * @param {function} fun   回调函数
         */
        addNativeCallback: function(method, fun) {
            nativeCall[method] = fun;
        },

         /**
         * 移除原生调用的方法
         * @param {string} method  方法名称
         * @param {function} fun   回调函数
         */
        removeNativeCallback: function(method) {
            if(nativeCall[method]) {
                nativeCall[method] = null;
            }
        },

        /**
         * 给原生方法调用通过addNativeCallback注册的函数,返回必须为字符串
         * @param {*} method 方法名称
         * @param {*} params 原生调用参数
         */
        nativeCallBack: function(method, params) {
            log("nativeCallBack method=" + method + " params=" + JSON.stringify(params))
            if (nativeCall[method]) {
                var res = nativeCall[method](params);
                if (typeof(res) !== 'string') {
                    res = JSON.stringify(res);
                }
                return res;
            }
            return "";
        },
        
        /**
         * 已经加载完成
         * @param {*} func 
         */
        onReady: function(func) {
            if(typeof(func) === 'function') {
                document.addEventListener('jDsServiceReady', func);
            }
        }
    };

    //用于加载完成后读取js配置
    mobile.addNativeCallback('getPageSetting', function(params) {
        return JSON.stringify(conf.setting);
    })

    //将mobile对象挂载到window全局
    win.jDsSdk = Object.create(mobile, {});


})(window);